home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Unix / Piper / Source / Piper.m < prev    next >
Text File  |  1993-01-25  |  10KB  |  231 lines

  1. #import <defaults/defaults.h>    //for NXArgv
  2. #import <appkit/Application.h> //for NXApp
  3. #import <appkit/Listener.h>    //for void NXUpdateDynamicServices(void)
  4. #import <appkit/Panel.h>       //for NXRunAlertPanel
  5. #import <appkit/Pasteboard.h>
  6. #import <libc.h>               //for mktemp
  7. #import <mach/mach.h>               //vm_deallocate
  8. #import <objc/Storage.h>
  9. #import <stdio.h>
  10. #import <stdlib.h>
  11. #import <strings.h>            //For strcmp
  12. #import <sys/dir.h>
  13. #import <sys/stat.h>
  14. #import <sys/param.h>          //For MAXPATHLEN
  15. //Maybe not using <appkit/appkit.h> goes faster... But it's a pain spelling
  16. //all this out. I want a CASE tool from NeXT!
  17.  
  18. #import "Piper.h"
  19. @implementation Piper
  20. -appDidInit:sender{
  21.   // Make us the object that service requests (piperMessage) get sent to.
  22.     [[NXApp appListener] setServicesDelegate:self];
  23.   return self;
  24.   }
  25. -piperMessage:(id)pb userData:(const char *)userData error:(char **)msg{
  26.   /*var*/
  27.     char        **pbtypes,*data,*outputData,
  28.                 scriptCmd[MAXPATHLEN];
  29.     int         length,err, i, outputLen, outputMaxlen;
  30.     FILE        *pipe;
  31.     NXStream    *pNXStream;
  32.     static char outputFile[]="/tmp/PipeXXXXXX";
  33.     struct stat sbuf;
  34.   if(!strcmp(userData,"NXUpdateDynamicServices")){
  35.     [self reloadScripts:self];
  36.     return self; 
  37.     }
  38.   for(pbtypes=(char **)[pb types];*pbtypes;pbtypes++){
  39.     if(   (*pbtypes==NXAsciiPboardType    /*Plain ASCII text*/)||
  40.           (*pbtypes==NXFilenamePboardType /*ASCII file name */)){
  41.       [pb readType:*pbtypes data:&data length:&length];
  42.       sprintf(scriptCmd,"%s/script",userData);
  43.       stat(scriptCmd, &sbuf);
  44.       if(!(sbuf.st_mode & 0111)){  
  45.         NXRunAlertPanel(NULL,"No execute permission on %s", 
  46.                         NULL,NULL,NULL,                scriptCmd);
  47.         exit(1);
  48.         }
  49.       mktemp(outputFile);
  50.       if(0){
  51.         }else if(*pbtypes==NXAsciiPboardType){
  52.           //For ascii pasteboard types, we just read the selection
  53.           //and pipe it through the given script. The output is collected
  54.           //in a temporary file.
  55.           //I think this should become an NXStream, somehow
  56.           //(needs another thread, hmmm)!!!
  57.           sprintf(scriptCmd,"%s/script >%s 2>/dev/console",
  58.                   userData,outputFile);
  59.           if((pipe=popen(scriptCmd,"w"))==NULL){
  60.             NXRunAlertPanel(NULL, "Command \"%s\" failed", 
  61.                             NULL,NULL,NULL,scriptCmd);
  62.             exit(1);
  63.             }
  64.           for(i=0;i<length;i++) putc(data[i], pipe);
  65.           if(err=pclose(pipe)){
  66.             NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d", 
  67.                             NULL,NULL,NULL, userData,                err);
  68.             }
  69.         }else if(*pbtypes==NXFilenamePboardType){
  70.           //Selection is a filename. Run the script with the filename
  71.           //as the only parameter. Any output is collected in the
  72.           //temporary file.
  73.           /*var*/ char *pchar;
  74.           while(pchar=data,pchar){
  75.             if(data=index(data,'\t')){ *data=0; data++; }
  76.             sprintf(scriptCmd, "%s/script \"%s\" >%s 2>/dev/console",
  77.                     userData, pchar, outputFile);
  78.             if(err=system(scriptCmd)){
  79.               NXRunAlertPanel(NULL,"Command \"%s\" returned error code %d. "
  80.                                    "Look at Console", 
  81.                               NULL,NULL,NULL, userData,                err);
  82.               }
  83.             }
  84.         }
  85.       //Now the fun bit. Any output from the script will be in the temporary
  86.       //file outputFile. Map the file in and paste the data out to the
  87.       //selection pasteboard.
  88.       pNXStream=NXMapFile(outputFile,NX_READONLY);
  89.       NXGetMemoryBuffer(pNXStream, &outputData, &outputLen, &outputMaxlen);
  90.       [pb declareTypes:&NXAsciiPboardType num:1 owner:self];
  91.       [pb writeType:NXAsciiPboardType data:outputData length:outputLen];
  92.       vm_deallocate(task_self(),(int)data,length);
  93.       sprintf(scriptCmd,"rm -f %s",outputFile);
  94.       system(scriptCmd);
  95.       return self;
  96.       }
  97.     }
  98.   //Didn't find one we liked (dropped out of pbtypes list).
  99.   NXRunAlertPanel(NULL,"Piper does not recognize pasteboard type %d", 
  100.                   NULL,NULL,NULL,*pbtypes);
  101.   return self;
  102.   }
  103. -reloadScripts:sender{
  104.   /*var*/
  105.     int keyFound,returnFound;
  106.     struct stat stats;
  107.     char option[256],keyOption[256],returnOption[256];
  108.     FILE *lspipe,*serviceFile,*optionsFile;
  109.   /*Make serviceFile your private services cache file.*/{
  110.     /*var*/ char serviceFilePath[MAXPATHLEN];
  111.     sprintf(serviceFilePath,"%s/.NeXT/services/Piper",getenv("HOME"));
  112.     if((serviceFile=fopen(serviceFilePath,"w"))==NULL){
  113.       NXRunAlertPanel(NULL,"Could not open service file %s",
  114.                       "Quit",NULL,NULL,                 serviceFilePath);
  115.       exit(1);
  116.       } //Shouldn't happen.
  117.     }
  118.   /*Make lspipe a pipe filled with script paths.*/{
  119.     /*var*/ char  executablePath[MAXPATHLEN],
  120.                   cmd           [MAXPATHLEN];
  121.     if(NXArgv[0][0]=='/'){
  122.         strcpy(executablePath,NXArgv[0]); *rindex(executablePath,'/')=0;
  123.       }else{
  124.         switch(NXRunAlertPanel( NULL,
  125.                                 "Please don't use the Update Dynamic Services "
  126.                                 "command in Piper's menu if it were "
  127.                                 "launched "
  128.                                 "from a shell with a partial path if you want "
  129.                                 "its SampleScripts to be included. "
  130.                                 "Maybe some programmer will give me a tool "
  131.                                 "to get the full path using the notion of "
  132.                                 "current directory or something? "
  133.                                 "He might then distribute this to the NeXT "
  134.                                 "programming community…",
  135.                                 "Quit","Cancel",NULL)){
  136.           case NX_ALERTDEFAULT: [NXApp terminate:self]; //break's not necessary
  137.           case NX_ALERTALTERNATE: return self;          //same
  138.           }
  139.       }
  140.     sprintf(cmd,"ls %s/SampleScripts/../SampleScripts 2>/dev/null "
  141.                 "| awk '{print \"%s/SampleScripts/\"$0}' 2>/dev/null; "
  142.                 "ls /LocalLibrary/Piper/../Piper 2>/dev/null "
  143.                 "| awk '{print \"/LocalLibrary/Piper/\"$0}' 2>/dev/null; "
  144.                 "ls %s/Library/Piper/../Piper 2>/dev/null "
  145.                 "| awk '{print \"%s/Library/Piper/\"$0}' 2>/dev/null",
  146.             executablePath, executablePath,getenv("HOME"),getenv("HOME"));
  147.     if((lspipe=popen(cmd,"r"))==NULL){
  148.       NXRunAlertPanel(NULL,"lspipe could not be opened",
  149.                       NULL,NULL,NULL);
  150.       exit(1);
  151.       } //If this happens, it's a bug.
  152.     }
  153.   /*Search for scripts.*/{
  154.     /*var*/ int count; //how many valid ones we found
  155.             char scriptDirPath[MAXPATHLEN],actualScriptPath[MAXPATHLEN];
  156.     for(count=0;
  157.         fgets(scriptDirPath,sizeof(scriptDirPath),lspipe)!=NULL;
  158.         count++){
  159.       scriptDirPath[strlen(scriptDirPath)-1]=0;
  160.       if(stat(scriptDirPath,&stats)<0||!(stats.st_mode&S_IFDIR)){
  161.         NXRunAlertPanel(NULL,"%s is not a directory!",
  162.                         NULL,NULL,NULL,scriptDirPath);
  163.         continue;
  164.         }
  165.       sprintf(actualScriptPath,"%s/script",scriptDirPath);
  166.       if(stat(actualScriptPath,&stats)<0||!(stats.st_mode & 0111)){
  167.         NXRunAlertPanel(NULL,"%s does not exist or is not executable", 
  168.                         NULL,NULL,NULL,actualScriptPath);
  169.         continue;
  170.         }
  171.       fprintf(serviceFile,"Message: piperMessage\n"
  172.                           "Port: Piper\n"
  173.                           "Menu Item: Piper/%s\n"
  174.                           "User Data: %s\n",
  175.               rindex(scriptDirPath,'/')+1,
  176.               scriptDirPath);
  177.       /*Look for options.*/{
  178.         /*var*/ char optionsPath[MAXPATHLEN];
  179.         sprintf(optionsPath,"%s/options",scriptDirPath);
  180.         keyFound=returnFound=0;
  181.         if((optionsFile=fopen(optionsPath,"r"))!=NULL){
  182.           while(fgets(option,sizeof(option),optionsFile)!=NULL){
  183.             if(!strncmp(option,"Key Equivalent",14)){
  184.                 strcpy(keyOption,option);
  185.                 keyFound++;
  186.               }else if(!strncmp(option,"Return Type",11)){
  187.                 strcpy(returnOption, option);
  188.                 returnFound++;
  189.               }else if(!strcmp(option,"Send Type: NXAsciiPboardType\n")){
  190.                 fprintf(serviceFile,option);
  191.               }else if(!strcmp(option,"Send Type: NXFilenamePboardType\n")){
  192.                 fprintf(serviceFile,option);
  193.               }else{
  194.                 NXRunAlertPanel(NULL,"Option\n"
  195.                                      "%s\n"
  196.                                      "not recognized in script\n"
  197.                                      "%s",
  198.                                 NULL,NULL,NULL,option,scriptDirPath);
  199.               }
  200.             }
  201.           fclose(optionsFile);
  202.           }
  203.         }
  204.       if(returnFound) fprintf(serviceFile,returnOption);
  205.       if(keyFound)    fprintf(serviceFile,keyOption);
  206.       /*always*/      fprintf(serviceFile,"\n");
  207.       }
  208.     pclose(lspipe);
  209.     fclose(serviceFile);
  210.     NXUpdateDynamicServices();
  211.     if(!count){
  212.       /*var*/ char somePath[MAXPATHLEN];
  213.       NXRunAlertPanel(NULL,"No valid scripts found",
  214.                       NULL,NULL,NULL);
  215.       sprintf(somePath,"%s/.NeXT/services/Piper",getenv("HOME"));
  216.       if(remove(somePath))
  217.         NXRunAlertPanel(NULL,
  218.           "Also, I could not get rid of ``%s''",
  219.           NULL,NULL,NULL,somePath);
  220.       exit(1);
  221.       }
  222.     }
  223.   NXRunAlertPanel(NULL,
  224.                   "Relaunch applications in which you want to use new "
  225.                   "names, if you haven't got a version (3.0 at least) "
  226.                   "in which NeXT fixed this.",
  227.                   NULL,NULL,NULL);
  228.   return self;
  229.   }
  230. @end
  231.